/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.Specialized;
using EnvDTE;
using System.Configuration;
using System.Globalization;
using System.Xml;
using DaveSexton.DocProject.Resources;
using System.Xml.XPath;

namespace DaveSexton.DocProject
{
	[Serializable]
	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
	public abstract class BufferedSettingsDictionaryBase<TKey, TValue> : SettingsDictionary<TKey, TValue>
	{
		#region Public Properties
		public abstract bool CanCommit { get; }

		public virtual bool UseBuffer
		{
			get
			{
				return buffered;
			}
			set
			{
				if (!value && Count > 0)
					throw new InvalidOperationException(Errors.CannotDisableBufferWithValues);

				buffered = value;
			}
		}

		public override TValue this[TKey key]
		{
			get
			{
				if (buffered)
					return base[key];
				else
					return GetCommittedValue(key);
			}
			set
			{
				if (buffered)
					base[key] = value;
				else if (!CanCommit)
					throw new InvalidOperationException(Errors.BufferedSettingsDictionaryCannotCommit);
				else
					SetCommittedValue(key, value);
			}
		}
		#endregion

		#region Private / Protected
		private bool buffered = true;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "DaveSexton.DocProject.SettingsDictionary`2<type parameter.TKey,type parameter.TValue>.#ctor")]
		protected BufferedSettingsDictionaryBase()
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "DaveSexton.DocProject.SettingsDictionary`2<type parameter.TKey,type parameter.TValue>.#ctor")]
		protected BufferedSettingsDictionaryBase(int capacity)
			: base(capacity)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "DaveSexton.DocProject.SettingsDictionary`2<type parameter.TKey,type parameter.TValue>.#ctor")]
		protected BufferedSettingsDictionaryBase(IEqualityComparer<TKey> comparer)
			: base(comparer)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "DaveSexton.DocProject.SettingsDictionary`2<type parameter.TKey,type parameter.TValue>.#ctor")]
		protected BufferedSettingsDictionaryBase(int capacity, IEqualityComparer<TKey> comparer)
			: base(capacity, comparer)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		protected BufferedSettingsDictionaryBase(CultureInfo culture)
			: base(culture)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		protected BufferedSettingsDictionaryBase(CultureInfo culture, int capacity)
			: base(culture, capacity)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		protected BufferedSettingsDictionaryBase(CultureInfo culture, IEqualityComparer<TKey> comparer)
			: base(culture, comparer)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for derived classes.
		/// </summary>
		protected BufferedSettingsDictionaryBase(CultureInfo culture, int capacity, IEqualityComparer<TKey> comparer)
			: base(culture, capacity, comparer)
		{
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="BufferedSettingsDictionary" /> class for deserialization.
		/// </summary>
		protected BufferedSettingsDictionaryBase(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
			: base(info, context)
		{
			buffered = info.GetBoolean("buffered");
		}
		#endregion

		#region Methods
		public override void Add(TKey key, TValue value)
		{
			if (buffered)
				base.Add(key, value);
			else if (!CanCommit)
				throw new InvalidOperationException(Errors.BufferedSettingsDictionaryCannotCommit);
			else
				SetCommittedValue(key, value);
		}

		public override bool ContainsKey(TKey key)
		{
			if (buffered)
				return base.ContainsKey(key);
			else
				return IsCommitted(key);
		}

		public override bool Remove(TKey key)
		{
			if (buffered)
				return base.Remove(key);
			else if (IsCommitted(key))
			{
				Delete(key);
				return true;
			}
			else
				return false;
		}
 
		public void Write(TKey name, TValue value)
		{
			Write(name, value, CultureInfo.InvariantCulture);
		}

		public string Read(TKey name)
		{
			return Read(name, CultureInfo.InvariantCulture, (string) null);
		}

		public override T Read<T>(TKey name, CultureInfo cultureInfo, T defaultValue)
		{
			TValue value;

			if (ContainsKey(name))
				value = this[name];
			else if (IsCommitted(name))
				value = GetCommittedValue(name);
			else
				return defaultValue;

			if (value == null)
				return defaultValue;
			else
				return ConvertType<TValue, T>(value, cultureInfo);
		}

		public abstract TValue GetCommittedValue(TKey name);

		public abstract void SetCommittedValue(TKey name, TValue value);

		public abstract bool IsDirty(TKey name);

		public abstract bool IsCommitted(TKey name);

		public abstract void Delete(TKey name);

		public virtual void Commit()
		{
			if (!CanCommit)
				throw new InvalidOperationException(Errors.BufferedSettingsDictionaryCannotCommit);

			foreach (KeyValuePair<TKey, TValue> pair in this)
				SetCommittedValue(pair.Key, pair.Value);

			this.Clear();
		}

		[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, SerializationFormatter = true)]
		public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
		{
			base.GetObjectData(info, context);

			info.AddValue("buffered", buffered);
		}
		#endregion
	}
}
